package com.ynsj.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ynsj.config.IdAutoConfiguration;
import com.ynsj.domain.Sms;
import com.ynsj.domain.UserAuthAuditRecord;
import com.ynsj.domain.UserAuthInfo;
import com.ynsj.geetest.GeetestLib;
import com.ynsj.model.*;
import com.ynsj.service.SmsService;
import com.ynsj.service.UserAuthAuditRecordService;
import com.ynsj.service.UserAuthInfoService;
import com.ynsj.vo.UserAuthInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ynsj.mapper.UserMapper;
import com.ynsj.domain.User;
import com.ynsj.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{

    @Autowired
    private UserAuthInfoService userAuthInfoService;

    @Autowired
    private UserAuthAuditRecordService userAuthAuditRecordService;

    @Autowired
    private GeetestLib geetestLib;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SmsService smsService;

    /**
     * 会员列表分页查询
     * @param userPage 分页参数
     * @param mobile 会员手机号
     * @param userId 会员ID
     * @param userName 会员名称
     * @param realName 会员真实姓名
     * @param status 会员状态
     * @return
     */
    @Override
    public Page<User> findByPage(Page<User> userPage, String mobile, Long userId, String userName, String realName, Integer status) {
        userPage.addOrder(OrderItem.desc("last_update_time"));
        return page(userPage,new LambdaQueryWrapper<User>()
                .like(!StringUtils.isEmpty(mobile),User::getMobile,mobile)
                .eq(userId!=null,User::getId,userId)
                .like(!StringUtils.isEmpty(userName),User::getUsername,userName)
                .like(!StringUtils.isEmpty(realName),User::getRealName,realName)
                .eq(status!=null,User::getStatus,status));
    }

    /**
     * 启用/禁用会员
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public boolean updateStatus(Long id, Integer status) {
        return update(new LambdaUpdateWrapper<User>()
                .eq(id!=null,User::getId,id)
                .set(status!=null,User::getStatus,status));
    }

    @Override
    public Page<User> findDirectPage(Page<User> userPage, Long userId) {
        return page(userPage,new LambdaQueryWrapper<User>().eq(userId!=null,User::getDirectInviteid,userId));
    }

    @Override
    public Page<User> findAuthByPage(Page<User> userPage, String mobile, Long userId, String userName, String realName, Integer reviewsStatus) {
        userPage.addOrder(OrderItem.desc("last_update_time"));
        return page(userPage,new LambdaQueryWrapper<User>()
                .like(!StringUtils.isEmpty(mobile),User::getMobile,mobile)
                .eq(userId!=null,User::getId,userId)
                .like(!StringUtils.isEmpty(userName),User::getUsername,userName)
                .like(!StringUtils.isEmpty(realName),User::getRealName,realName)
                .eq(reviewsStatus!=null,User::getReviewsStatus,reviewsStatus));
    }

    /**
     * 根据id查询用户认证详情
     *
     * @param id
     * @return
     */
    @Override
    public UserAuthInfoVo getUserInfoById(Long id) {
        UserAuthInfoVo userAuthInfoVo = new UserAuthInfoVo();
        List<UserAuthInfo> userAuthInfoList = null;
        List<UserAuthAuditRecord> userAuthAuditRecords = null;
        User user = getById(id);
        if (user!=null){
            if (user.getReviewsStatus()==null || user.getReviewsStatus()==0){
                userAuthAuditRecords = Collections.emptyList();
                userAuthInfoList = userAuthInfoService.findByUserId(id);
            }else{
                userAuthAuditRecords = userAuthAuditRecordService.findByUserId(id);
                UserAuthAuditRecord record = userAuthAuditRecords.get(0);
                Long authCode = record.getAuthCode();
                userAuthInfoList = userAuthInfoService.findByAuthCode(authCode);
            }
        }
        userAuthInfoVo.setUser(user);
        userAuthInfoVo.setUserAuthInfoList(userAuthInfoList);
        userAuthInfoVo.setAuthAuditRecordList(userAuthAuditRecords);
        return userAuthInfoVo;
    }

    /**
     * 审核用户照片信息
     *
     * @param id
     * @param authStatus
     * @param authCode
     * @param remark
     * @return
     */
    @Override
    @Transactional
    public void updateAuthStatus(Long id, Integer authStatus, Long authCode, String remark) {
        log.info("开始修改用户的审核状态,当前用户{},用户的审核状态{},图片的唯一code{}",id,authStatus,authCode);
        User user = getById(id);
        if (user!=null){
            //修改用户的审核状态
            user.setReviewsStatus(authStatus);
            updateById(user);
        }
        //在审核记录表中添加记录
        UserAuthAuditRecord userAuthAuditRecord = new UserAuthAuditRecord();
        userAuthAuditRecord.setUserId(id);
        userAuthAuditRecord.setAuthCode(authCode);
        userAuthAuditRecord.setStatus(authStatus.byteValue());
        userAuthAuditRecord.setRemark(remark);
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        userAuthAuditRecord.setAuditUserId(Long.valueOf(userId));
        userAuthAuditRecord.setAuditUserName("-----");//此处需要远程调用 admin-service 没有事务

        userAuthAuditRecordService.save(userAuthAuditRecord);

    }

    /**
     * 用户实名认证
     *
     * @param userCheckForm 用户认证数据对象
     * @return
     */
    @Override
    public boolean identifyCheck(UserCheckForm userCheckForm) {
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(Long.valueOf(userId));
        Assert.notNull(user,"要认证的用户不存在");
        //极验认证
        checkForm(userCheckForm);
        //实名认证
        boolean check = IdAutoConfiguration.check(userCheckForm.getRealName(), userCheckForm.getIdCard());
        if(!check){
            throw new RuntimeException("该用户信息有误,请检查后重新提交认证");
        }
        //认证返回成功,填充认证属性
        user.setAuthtime(new Date());//认证时间
        user.setAuthStatus((byte) 1);//认证状态
        user.setRealName(userCheckForm.getRealName());//用户真实姓名
        user.setIdCard(userCheckForm.getIdCard());//用户证件号
        user.setIdCardType(userCheckForm.getIdCardType());//用户证件类型
        return updateById(user);
    }

    /**
     * 用户进行认证
     *
     * @param singletonList 用户图片地址
     */
    @Override
    @Transactional
    public void authUser(List<String> singletonList) {
        if (CollectionUtils.isEmpty(singletonList)){
            throw new RuntimeException("用户的身份证信息为空");
        }
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(Long.valueOf(userId));
        if (user == null){
            throw new RuntimeException("请登入正确的用户");
        }
        long authCode = snowflake.nextId();
        List<UserAuthInfo> userAuthInfoList = new ArrayList<>(singletonList.size());
        for (int i = 0; i <singletonList.size() ; i++) {//按照属性排列 1.正面 2.反面 3.手持
            UserAuthInfo userAuthInfo = new UserAuthInfo();
            userAuthInfo.setUserId(Long.valueOf(userId));
            userAuthInfo.setImageUrl(singletonList.get(i));
            userAuthInfo.setSerialno(i+1);
            userAuthInfo.setAuthCode(authCode);//是一组身份信息标识 三个图片为一组
            userAuthInfoList.add(userAuthInfo);
        }
        userAuthInfoService.saveBatch(userAuthInfoList);
        user.setReviewsStatus(0);//等待审核
        updateById(user);//更新用户状态
    }

    /**
     * 修改用户的手机号
     *
     * @param updatePhoneParam
     * @return
     */
    @Override
    public boolean updatePhone(UpdatePhoneParam updatePhoneParam) {
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(Long.valueOf(userId));
        String oldMobile = user.getMobile();//验证旧手机号码的验证码
        String oldMobileCoed = stringRedisTemplate.opsForValue().get("SMS:VERIFY_OLD_PHONE:" + oldMobile);
        if (!StringUtil.equals(oldMobileCoed,updatePhoneParam.getOldValidateCode())){
            throw new IllegalArgumentException("旧手机的验证码错误");
        }
        String newPhoneCode = stringRedisTemplate.opsForValue().get("SMS:CHANGE_PHONE_VERIFY:" + updatePhoneParam.getValidateCode());
        if (!StringUtil.equals(newPhoneCode,updatePhoneParam.getValidateCode())){
            throw new IllegalArgumentException("新手机的验证码错误");
        }
        user.setMobile(updatePhoneParam.getNewMobilePhone());
        return updateById(user);
    }

    /**
     * 检查新的手机号是否可用，若可用，给新手机号发送验证码
     *
     * @param mobile      新的手机号
     * @param countryCode 国家代码
     * @return
     */
    @Override
    public boolean checkTel(String mobile, String countryCode) {
        int count = count(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile).eq(User::getCountryCode, countryCode));
        if(count>0){
            throw new IllegalArgumentException("该手机号已经被占用");
        }
        Sms sms = new Sms();
        sms.setMobile(mobile);
        sms.setCountryCode(countryCode);
        sms.setTemplateCode("CHANGE_PHONE_VERIFY");//模板代码
        return smsService.sendSms(sms);
    }

    /**
     * 修改用户的登录密码
     *
     * @param userId           用户的ID
     * @param updateLoginParam 修改密码的表单参数
     * @return
     */
    @Override
    public boolean updateUserLoginPwd(Long userId, UpdateLoginParam updateLoginParam) {
        User user = getById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户的Id错误");
        }
        // 1 校验之前的密码 数据库的密码都是我们加密后的密码.-->
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(updateLoginParam.getOldpassword(), user.getPassword());
        if (!matches) {
            throw new IllegalArgumentException("用户的原始密码输入错误");
        }
        // 2 校验手机的验证码
        String validateCode = updateLoginParam.getValidateCode();
        String phoneValidateCode = stringRedisTemplate.opsForValue().get("SMS:CHANGE_LOGIN_PWD_VERIFY:" + user.getMobile());//"SMS:CHANGE_LOGIN_PWD_VERIFY:111111"
        if (!validateCode.equals(phoneValidateCode)) {
            throw new IllegalArgumentException("手机验证码错误");
        }
        user.setPassword(bCryptPasswordEncoder.encode(updateLoginParam.getNewpassword())); // 修改为加密后的密码
        return updateById(user);
    }

    /**
     * 修改用户的交易密码
     *
     * @param userId           用户的Id
     * @param updateLoginParam 修改交易密码的表单参数
     * @return
     */
    @Override
    public boolean updateUserPayPwd(Long userId, UpdateLoginParam updateLoginParam) {
        // 1 查询之前的用户
        User user = getById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户的Id错误");
        }
        // 1 校验之前的密码 数据库的密码都是我们加密后的密码.-->
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        boolean matches = bCryptPasswordEncoder.matches(updateLoginParam.getOldpassword(), user.getPaypassword());
        if (!matches) {
            throw new IllegalArgumentException("用户的原始密码输入错误");
        }
        // 2 校验手机的验证码
        String validateCode = updateLoginParam.getValidateCode();
        String phoneValidateCode = stringRedisTemplate.opsForValue().get("SMS:CHANGE_PAY_PWD_VERIFY:" + user.getMobile());//"SMS:CHANGE_LOGIN_PWD_VERIFY:111111"
        if (!validateCode.equals(phoneValidateCode)) {
            throw new IllegalArgumentException("手机验证码错误");
        }
        user.setPaypassword(bCryptPasswordEncoder.encode(updateLoginParam.getNewpassword())); // 修改为加密后的密码
        return updateById(user);
    }

    /**
     * 重置用户的支付密码
     *
     * @param userId                用户的Id
     * @param unsetPayPasswordParam 重置的表单参数
     * @return 是否重置成功
     */
    @Override
    public boolean unsetPayPassword(Long userId, UnsetPayPasswordParam unsetPayPasswordParam) {
        User user = getById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户的Id 错误");
        }
        String validateCode = unsetPayPasswordParam.getValidateCode();
        String phoneValidate = stringRedisTemplate.opsForValue().get("SMS:FORGOT_PAY_PWD_VERIFY:" + user.getMobile());
        if (!validateCode.equals(phoneValidate)) {
            throw new IllegalArgumentException("用户的验证码错误");
        }
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        user.setPaypassword(bCryptPasswordEncoder.encode(unsetPayPasswordParam.getPayPassword()));

        return updateById(user);
    }

    private void checkForm(UserCheckForm userCheckForm) {
        GeetestForm.check(userCheckForm,geetestLib,redisTemplate);
    }

    @Override
    public User getById(Serializable id) {
        User user = super.getById(id);
        if (user==null){
            throw new RuntimeException("请输入正确的用户ID");
        }
        Byte seniorAuthStatus = null;
        String seniorAuthDesc = "";
        Integer reviewsStatus = user.getReviewsStatus();//会员审核状态,1通过,2拒绝,0,待审核
        if (reviewsStatus==null){
            seniorAuthStatus = 3;
            seniorAuthDesc = "资料未填写";
        }else{
            switch (reviewsStatus){
                case 0 :
                    seniorAuthStatus = 0;
                    seniorAuthDesc = "资料待审核";
                    break;
                case 1 :
                    seniorAuthStatus = 1;
                    seniorAuthDesc = "资料审核通过";
                    break;
                case 2 :
                    seniorAuthStatus = 2;
                    List<UserAuthAuditRecord> records = userAuthAuditRecordService.findByUserId(user.getId());
                    if (!CollectionUtils.isEmpty(records)){
                        UserAuthAuditRecord userAuthAuditRecord = records.get(0);
                        seniorAuthDesc = userAuthAuditRecord.getRemark();
                    }else{
                        seniorAuthDesc = "原因未知";
                    }
                    break;
            }
        }
        user.setSeniorAuthStatus(seniorAuthStatus);//会员的高级认证状态: 0:审核中,1:通过,2:拒绝,3:未填写
        user.setSeniorAuthDesc(seniorAuthDesc);//会员高级认证拒绝原因
        return user;
    }
}
